// Fireworks JavaScript Command // Install by copying to Fireworks/Configuration/Commands/ // Aaron Beall 2008-2011 - http://abeall.com // Version 1.3.3 var dom = fw.getDocumentDOM(); var sel = [].concat(fw.selection); function SharpenPoints(){ // require active document if(!dom) return false; // sharpen selected adjacent points var straightened = false, subselect = fw.activeTool == 'Subselection', MAX_POINT_COORD = Math.max(dom.width,dom.height)*10; var nodes, node, nextNode, prevNode, nextNextNode, isClosed, pre1, pre2, suc1, suc2, preSlope, sucSlope, pt; var newNodes, newNode; for(var s = 0; s < sel.length; s++){ for(var c = 0; c < sel[s].contours.length; c++){ nodes = sel[s].contours[c].nodes; isClosed = sel[s].contours[c].isClosed; newNodes = []; var nlen = nodes.length; for(var n = 0; n < nlen; n++){ node = nodes[n]; newNodes.push(copyNode(node)); newNode = newNodes[newNodes.length - 1]; if(!isClosed && n == nodes.length - 1) continue; if(node.isSelectedPoint || !subselect){ nextNode = n == nodes.length - 1 ? nodes[0] : nodes[n + 1]; if(nextNode.isSelectedPoint || !subselect){ // preceding line pre1 = node; if(node.x != node.predX || node.y != node.predY) // from pred handle to node pre2 = {x:node.predX, y:node.predY}; else // from previous node to this node pre2 = nodes[n - 1] || nodes[nodes.length - 1]; preSlope = pointPointF(pre1, pre2); // succeeding line suc1 = nextNode; if(nextNode.x != nextNode.succX || nextNode.y != nextNode.succY) // from succ handle to node suc2 = {x:nextNode.succX, y:nextNode.succY}; else // from node to next node suc2 = n == nodes.length - 1 ? nodes[1] : nodes[n + 2] || nodes[0]; sucSlope = pointPointF(suc1, suc2); // based on the two lines, find intersection if(pre1.x == pre2.x){ pt = intersectionY(pre1.x, sucSlope.m, sucSlope.b); }else if(suc1.x == suc2.x){ pt = intersectionY(suc1.x, preSlope.m, preSlope.b); }else{ pt = intersection(preSlope.m, preSlope.b, sucSlope.m, sucSlope.b); } // skip parallel lines if(pt.x < -MAX_POINT_COORD || pt.x > MAX_POINT_COORD || pt.y < -MAX_POINT_COORD || pt.y > MAX_POINT_COORD) continue; // merge two points into one point at intersection newNode.isCurvePoint = false; newNode.x = newNode.predX = newNode.succX = pt.x; newNode.y = newNode.predY = newNode.succY = pt.y; if(node.predX != node.x || node.predY != node.y){ // if there were pred handles on the node, leave them newNode.predX = node.predX; newNode.predY = node.predY; } if(nextNode.succX != nextNode.x || nextNode.succY != nextNode.y){ // if there were succ handles on the nextNode, leave them as succ nodes on the new node newNode.succX = nextNode.succX; newNode.succY = nextNode.succY; } n++; // skip next node, it has be merged into this one if(n==nodes.length) newNodes.shift(); else if(n==0) node.isSelectedPoint = false; straightened = true; } } } // apply new nodes if(newNodes.length != nodes.length){ sel[s].contours[c] = new Contour(); sel[s].contours[c].isClosed = isClosed; for(var n = 0; n < newNodes.length; n++){ sel[s].contours[c].nodes[n] = new ContourNode(); pasteNode(sel[s].contours[c].nodes[n], newNodes[n]); } } } } if(!straightened) return alert('This operation produced no output. You must select two adjacent points, the two points will attempt to be merged into one corner point -- this is most commonly used to reverse the effects of Fillet Points.'); } try{ SharpenPoints(); }catch(e){ alert([e, e.lineNumber, e.fileName].join("\n")) }; // copy node function copyNode(pt){ var ptCopy = {} copyProps(ptCopy, pt, ["x", "y", "succX", "succY", "predX", "predY", "randomSeed", "isSelectedPoint", "isCurvePoint", "name"]); ptCopy.dynamicInfo = []; for(var i = 0; i < pt.dynamicInfo.length; i++) ptCopy.dynamicInfo[i] = copyProps({}, pt.dynamicInfo[i], ["pressure", "duration", "velocity"]); return ptCopy; } // paste node function pasteNode(pt, ptCopy){ copyProps(pt, ptCopy, ["x", "y", "succX", "succY", "predX", "predY", "randomSeed", "isSelectedPoint", "isCurvePoint", "name"]); var dynamicInfo = []; for(var i = 0; i < ptCopy.dynamicInfo.length; i++) dynamicInfo.push(copyProps(new ContourNodeDynamicInfo(), ptCopy.dynamicInfo[i], ["pressure", "duration", "velocity"])); pt.dynamicInfo = dynamicInfo; return pt; } // copy props by name function copyProps(targetObj, sourceObj, props){ var p = props.length; while(p--) targetObj[props[p]] = sourceObj[props[p]]; return targetObj; } // get the angle in radians between two points function getAngleRadians(p1,p2){ return -Math.atan2(p1.x-p2.x, p1.y-p2.y); } // this function returns the slope and y-intercept of the line going thru x1,y1 and x2,y2 function pointPointF(p1,p2) { //alert([p1.toSource(),p2.toSource()].join('\n')); var m = (p1.y-p2.y)/(p1.x-p2.x); var b = p1.y-p1.x*m; return {m:m,b:b}; } // this function returns the x,y point at the intersection of lines with slope and y-intercept m1,b1 and m2,b2. function intersection(m1,b1,m2,b2) { if (m1!=m2) { var x = (b2-b1)/(m1-m2); var y = m1*x+b1; return {x:x,y:y}; } else { return null; } } // this function returns the x,y point at the intersection of line x and line with slope and y-intercept m,b function intersectionY(x,m,b) { var y = m*x+b; return {x:x,y:y}; }